package vip.manda.framework.web.server;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.ClassUtil;
import io.undertow.Handlers;
import io.undertow.Undertow;
import io.undertow.servlet.Servlets;
import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.DeploymentManager;
import io.undertow.servlet.api.ServletInfo;
import vip.manda.framework.config.UndertowConfig;
import vip.manda.framework.config.WebConfig;
import vip.manda.framework.core.Application;
import vip.manda.framework.core.Configs;
import vip.manda.framework.log.Log;
import vip.manda.framework.log.LogFactory;
import vip.manda.framework.web.http.CenterServlet;
import vip.manda.framework.web.http.Interceptor;

import javax.servlet.*;

/**
 * @author hongda.li 2022-03-31 20:06
 */
public class UndertowServer extends WebServer {
    private static final Log log = LogFactory.getLog();
    private final String context;
    private final int port;
    private Undertow undertow;
    private DeploymentManager manager;
    public UndertowServer(){
        initConfig();
        String context = Configs.getStr(WebConfig.CONTEXT);
        this.context = "".equals(context) ? "/" : context;
        this.port = Configs.getInt(WebConfig.PORT);
    }

    private void initConfig() {
        Configs.setDefaultConfig(UndertowConfig.HOST, UndertowConfig.Values.HOST);
        Configs.setDefaultConfig(UndertowConfig.THREAD_IO, UndertowConfig.Values.THREAD_IO);
        Configs.setDefaultConfig(UndertowConfig.THREAD_WORK, UndertowConfig.Values.THREAD_WORK);
        Configs.setDefaultConfig(UndertowConfig.BUFFER_SIZE, UndertowConfig.Values.BUFFER_SIZE);
        Configs.setDefaultConfig(UndertowConfig.DIRECT_BUFFERS, UndertowConfig.Values.DIRECT_BUFFERS);
    }

    @Override
    public void startServer() {
        try {
            start();
        } catch (ServletException e) {
            log.error("Undertow start error");
        }
    }

    @Override
    public void stopServer() {
        try {
            this.undertow.stop();
            this.manager.stop();
            this.manager.undeploy();
        } catch (ServletException e) {
            log.error("Undertow stop error");
            e.printStackTrace();
        }
    }

    private DeploymentInfo configDeploymentInfo() {
        ServletInfo servletInfo = Servlets.servlet(CenterServlet.class).addMapping("/*");
        return Servlets.deployment()
                .setClassLoader(ClassUtil.getClassLoader())
                .setContextPath(context)
                .setDeploymentName(Application.getMain().getName())
                .addServlets(servletInfo)
                .addFilter(Servlets.filter(Interceptor.class.getName(), Interceptor.class))
                .addFilterUrlMapping(Interceptor.class.getName(), "/*", DispatcherType.REQUEST);
    }

    public void start() throws ServletException {
        DeploymentManager manager = Servlets.defaultContainer().addDeployment(configDeploymentInfo());
        this.manager = manager;
        this.manager.deploy();
        this.undertow = Undertow.builder()
                .addHttpListener(port, Configs.getStr(UndertowConfig.HOST))
                .setHandler(Handlers.path(Handlers.redirect(context)).addPrefixPath(context, manager.start()))
                .setIoThreads(Configs.getInt(UndertowConfig.THREAD_IO))
                .setWorkerThreads(Configs.getInt(UndertowConfig.THREAD_WORK))
                .setBufferSize(Configs.getInt(UndertowConfig.BUFFER_SIZE))
                .setDirectBuffers(Configs.getBool(UndertowConfig.DIRECT_BUFFERS))
                .build();
        this.undertow.start();
        log.info("Server listen on[http://{}:{}{}]", NetUtil.getLocalhostStr(), port, context);
    }
}
